# Copyright (c) 2017, Nordic Semiconductor ASA
# 
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 
#    1. Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
# 
#    2. Redistributions in binary form must reproduce the above
#       copyright notice, this list of conditions and the following
#       disclaimer in the documentation and/or other materials provided
#       with the distribution.
# 
#    3. Neither the name of Nordic Semiconductor ASA nor the names of
#       its contributors may be used to endorse or promote products
#       derived from this software without specific prior written
#       permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NORDIC
# SEMICONDUCTOR ASA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.

import time, os, logging, traceback, threading
import logging.handlers as logHandlers

#################################################################
# This file contains the logger. To log a line, simply write     #
# 'logging.[level]("whatever you want to log")'                    #
# [level] is one of {info, debug, warning, error, critical,        #
#     exception}                                                    #
# See python logging documentation                                #
# As long as Logger.initLogger has been called beforehand, this    #
# will result in the line being appended to the log file        #
#################################################################

try:
    # C:\Users\Austin\AppData\Roaming\Nordic Semiconductor\Sniffer\logs
    logFilePath = os.path.join(os.getenv('appdata'), 'Nordic Semiconductor', 'Sniffer', 'logs')
except AttributeError:
    logFilePath = "/tmp/logs"

logFileName = os.path.join(logFilePath, 'log.txt')

logHandler = None
logHandlerArray = []
logFlusher = None

myMaxBytes = 1000000


# Ensure that the directory we are writing the log file to exists.
# Create our logfile, and write the timestamp in the first line.
def initLogger():
    try:
        # First, make sure that the directory exists
        if not os.path.isdir(logFilePath):
            os.makedirs(logFilePath)

        # If the file does not exist, create it, and save the timestamp
        if not os.path.isfile(logFileName):
            with open(logFileName, "wb") as f:
                f.write(str(time.time()) + os.linesep)

        global logFlusher
        global logHandlerArray

        logHandler = MyRotatingFileHandler(logFileName, mode='a', maxBytes=myMaxBytes, backupCount=3)
        logFormatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s', datefmt='%d-%b-%Y %H:%M:%S (%z)')
        logHandler.setFormatter(logFormatter)
        logger = logging.getLogger()
        logger.addHandler(logHandler)
        logger.setLevel(logging.INFO)
        logFlusher = LogFlusher(logHandler)
        logHandlerArray.append(logHandler)
    except:
        print ("LOGGING FAILED")
        print((traceback.format_exc()))
        raise


def shutdownLogger():
    logging.shutdown()


# Clear the log (typically after it has been sent on email)
def clearLog():
    try:
        logHandler.doRollover()
    except:
        print ("LOGGING FAILED")
        raise


# Returns the timestamp residing on the first line of the logfile. Used for checking the time of creation
def getTimestamp():
    try:
        with open(logFileName, "r") as f:
            f.seek(0)
            return f.readline()
    except:
        print ("LOGGING FAILED")


def addTimestamp():
    try:
        with open(logFileName, "a") as f:
            f.write(str(time.time()) + os.linesep)
    except:
        print ("LOGGING FAILED")


# Returns the entire content of the logfile. Used when sending emails
def readAll():
    try:
        text = ""
        with open(logFileName, "r") as f:
            text = f.read()
        return text
    except:
        print ("LOGGING FAILED")


def addLogHandler(logHandler):
    global logHandlerArray
    logger = logging.getLogger()
    logger.addHandler(logHandler)
    logger.setLevel(logging.INFO)
    logHandlerArray.append(logHandler)


class MyRotatingFileHandler(logHandlers.RotatingFileHandler):
    def doRollover(self):
        try:
            logHandlers.RotatingFileHandler.doRollover(self)
            addTimestamp()
            self.maxBytes = myMaxBytes
        except:
            # There have been permissions issues with the log files.
            self.maxBytes += int(myMaxBytes / 2)


class LogFlusher(threading.Thread):
    def __init__(self, logHandler):
        threading.Thread.__init__(self)

        self.daemon = True
        self.handler = logHandler
        self.exit = False

        self.start()

    def run(self):
        while not self.exit:
            time.sleep(10)
            self.doFlush()

    def doFlush(self):
        self.handler.flush()
        os.fsync(self.handler.stream.fileno())

    def stop(self):
        self.exit = True


if __name__ == '__main__':
    initLogger()
    for i in range(50):
        logging.info("test log no. " + str(i))
        print(("test log no. ", i))
